//
// Created by fyniny on 12/23/18.
//

#include "spooling.h"
#include <fstream>
#include "dispatchprocess.h"

bool spooling::isEmpty() {
    return m_req_status == OUTPUT_EMPTY;
}

bool spooling::isFull() {
    return m_req_status == OUTPUT_FULL;
}

spooling::spooling(int max_output, PCB pcb) : Base(max_output, &pcb) {
//   初始化文件输出首行
    outBuffer << "order\t\t\tprocess\t\t\tlength\t\t\tfile container\n";
    m_in = m_out = 0;
    m_req_status = OUTPUT_EMPTY;
}

void spooling::Output() {
    static int order = 1;
    // 若输出队列为空，阻塞自己
    if (isEmpty()) {
        SHOW_WAKE;
        setProcessStatus(PROCESS_WAIT_EMPTY_OUTPUT_BLOCK);
        return;
    }
    std::ostream &cout = std::cout;
    cout << "order                 process                 length                 file container\n";
    while (!isEmpty() && !isDied()) {
        Buffer *buffer = nullptr;
        ReqBlock &req = frontReqBlock(&buffer);
        cout << order << "\t\t\t" << req.req_name << "\t\t\t" << req.length << "\t\t\t" << buffer->getBuffer() << "\n";
        outBuffer << order << "\t\t\t" << req.req_name << "\t\t\t" << req.length << "\t\t\t" << buffer->getBuffer() << "\n";
        order++;
        m_buffer[req.req_name].push_back(*buffer);
        this->output(1);
        popReqBlock();
    }
}
// 将输出进程的输出信息保存至请求队列
int spooling::pushReqBlock(ReqBlock &req, Buffer &buffer) {
    if (isFull()) {
        return PROCESS_WAIT_FULL_OUTPUT_BLOCK;
    }
    m_reqblock[m_in] = req;
    m_reqBuffer[m_in] = buffer;
    m_in = (++m_in) % MAX_OUTPUT_BLOCK;
    if (m_in == m_out) {
        m_req_status = OUTPUT_FULL;
    } else if (m_req_status == OUTPUT_EMPTY) {
        m_req_status = OUTPUT_RUNNING;
    }
    return 0;
}
ReqBlock &spooling::frontReqBlock(Buffer **buffer) {
    assert(!isEmpty());
    *buffer = m_reqBuffer + m_out;
    return m_reqblock[m_out];
}
void spooling::popReqBlock() {
    m_out = ((++m_out) % MAX_OUTPUT_BLOCK);
    if (m_out == m_in) {
        m_req_status = OUTPUT_EMPTY;
        SHOW_WAKE;
        setProcessStatus(PROCESS_WAIT_EMPTY_OUTPUT_BLOCK);
    }

}

void spooling::run(void *arg_process) {
    if (isEmpty()) {
        return;
    }
    // 执行输出
    Output();
    // 唤醒程序
    auto *dis = (DispathProcess *) arg_process;
    for (size_t i = 0;; i++) {
        Base *base = dis->getInstance(i);
        if (base == nullptr) {
            break;
        }
        if (base->getProcessID() == getProcessID()) {
            continue;
        }
        if (PROCESS_RESULT == base->getProcessStatus()) {
            continue;
        }
        SHOW_WAKE_2;
        base->setProcessStatus(PROCESS_EXECUTABLE);
    }
}

int spooling::request(ReqBlock &req, Buffer &buffer) {

    if (isFull()) {
        return PROCESS_WAIT_FULL_OUTPUT_BLOCK;
    }
    int status;
    if (0 != (status = pushReqBlock(req, buffer))) {
        return status;
    }

// 将spooling进程改为可执行态
    if (getProcessStatus() == PROCESS_WAIT_EMPTY_OUTPUT_BLOCK) {
        SHOW_WAKE;
        setProcessStatus(PROCESS_EXECUTABLE);
        m_req_status = OUTPUT_RUNNING;
    }
    return 0;
}

spooling::~spooling() {
    std::fstream file("out.txt", std::ios::out);
    file << outBuffer.str().c_str();
    file.close();
}
